/*---------------------------------------------------------------------------
	ZaRan	-	A Totallly Automatic CFD Software
	Copyright (C) ,Since 2020
-------------------------------------------------------------------------------
License
	This file is part of ZaRan.

!	@file		gird.h
!	@brief	the purpose of this file.
!	@author	Chen Jie.
\*---------------------------------------------------------------------------*/
#pragma once
#include"Basic/include/CommonPara.h"
#include"grid/include/grid.h"
#include<iostream>
#include<cmath>
#include<algorithm>
#include<memory>


//vector<int> GridNode::GetNeiborNodeGridIndex() const
//{
//	vector<int> grid_index(neibor_node_grid_.size());
//	for (size_t iGrid = 0; iGrid < neibor_node_grid_.size(); ++iGrid)
//	{
//		grid_index[iGrid] = neibor_node_grid_[iGrid]->GetIndex();
//	}
//	return grid_index;
//}
Grid::Grid()
{
	dim_ = Dimension::two;
	node_.resize(0);
}
Grid::Grid(const Grid& mesh)
{
	dim_ = mesh.dim_;
	node_ = mesh.node_;
}
void Grid::SetNode(vector<GridNode>& node)
{
	node_.resize(node.size());
	for (size_t iNode = 0; iNode < node_.size(); ++iNode)
	{
		if (node[iNode].GetGridIndex() != this->GetIndex())
		{
			node_[iNode] = GridNode(this, iNode, *node[iNode].GetCoord());
		}
		else
		{
			node_[iNode] = node[iNode];
		}
	}
}
void Grid::SetElement(const vector<GridElement>& element)
{
	element_ = element;
}
void Grid::SetFace(const vector<GridFace>& face)
{
	face_ = face;
}
void Grid::SetDim(Dimension dim)
{
	dim_ = dim;
}
void Grid::SetDim(int dim)
{
	if (dim == 2)
		dim_ == Dimension::two;
	else if (dim == 3)
		dim_ == Dimension::three;
}
Dimension Grid::GetDim() const
{
	return dim_;
}
GridNode* Grid::GetNode(size_t iNode)
{
	return &node_[iNode];
}
Point* Grid::GetNodeCoord(size_t iNode)
{
	return node_[iNode].GetCoord();
}
int Grid::GetNodeNum() const
{
	return node_.size();
}
int Grid::GetNeiborNodeNum(size_t iNode)
{
	return node_[iNode].GetNeiborNodePtr()->size();
}
vector< GridNode*>* Grid::GetNeiborNodePtrVec(size_t iNode)
{
	return node_[iNode].GetNeiborNodePtr();
}
void Grid::SetNeiborNode(size_t iNode, const vector<size_t>& neibor_node_index, const vector<Grid*>& neibor_node_grid)
{

	if (iNode > node_.size())
		return;
	vector< GridNode*>neiborNodePtrVec;
	neiborNodePtrVec.resize(neibor_node_index.size());
	for (size_t iNeib = 0; iNeib < neibor_node_index.size(); ++iNeib)
	{
		neiborNodePtrVec[iNeib] = neibor_node_grid[iNeib]->GetNode(neibor_node_index[iNeib]);
	}
	node_[iNode].SetNeiborNode(neiborNodePtrVec);
}
void Grid::SetBoundNodeIndex()
{
	for (size_t iNode = 0; iNode < node_.size(); ++iNode)
	{
		if (*node_[iNode].GetNodeType() != BoundType::notbound)
			boundNodeIndexVec_.push_back(iNode);
	}
}
void Grid::ReorderNeiborNode()
{

	for (size_t iNode = 0; iNode < node_.size(); ++iNode)
	{
		node_[iNode].ReoderNeibor();
		
	}
}
void Grid::CalCoordTrans()
{
	for (size_t iNode = 0; iNode < this->GetNodeNum(); ++iNode)
	{
		vector<CoordTrans>& nodeCoordTrans = *node_[iNode].GetCoordTranCoef();
		int neiborNodeNum = GetNeiborNodeNum(iNode);
		vector<Point>neiborNodeCoord(neiborNodeNum);
		vector< GridNode*>&neiborNodePtr = *node_[iNode].GetNeiborNodePtr();
		if (neiborNodeNum == 4)
		{
			for (size_t iNeib = 0; iNeib < neiborNodeNum; ++iNeib)
			{
				neiborNodeCoord[iNeib] = *neiborNodePtr[iNeib]->GetCoord();
			}
			nodeCoordTrans.push_back(CoordTrans(2, neiborNodeCoord));
		}
		else if (neiborNodeNum == 3)
		{
			nodeCoordTrans.resize(12);
			neiborNodeCoord.resize(4);
			for (size_t iMethod = 0; iMethod < neiborNodeNum; ++iMethod)
			{
				for (size_t iNeib = 0; iNeib < 4; ++iNeib)
				{
					neiborNodeCoord[iNeib] = *neiborNodePtr[ThreeNeiborMethod[iMethod][iNeib]]->GetCoord();
				}
				nodeCoordTrans[iMethod] = CoordTrans(2, neiborNodeCoord);
			}
		}
	}
}
vector<CoordTrans>* Grid::GetNodeCoordTrans(size_t iNode)
{
	return node_[iNode].GetCoordTranCoef();
}
vector<size_t>* Grid::GetElementNodeIndex(size_t iElem)
{
	return element_[iElem].GetNodeIndexVec();
}
BoundType* Grid::GetNodeType(int iNode)
{
	return node_[iNode].GetNodeType();
}
void Grid::SetData(size_t iNode, size_t idata, const double& dataValue)
{
	nodeDataVec_[iNode].UpdateData(idata,dataValue) ;
}
double* Grid::GetDataValuePtr(size_t iNode, size_t idata)
{
	return nodeDataVec_[iNode].GetDataValuePtr(idata);
}
void Grid::InitData()
{
	nodeDataVec_.resize(node_.size());
}
void Grid::SetData(size_t iNode, DataField& dataSet)
{
	nodeDataVec_[iNode] = dataSet;
}
DataField* Grid::GetDataField(size_t iNode)
{
	return &nodeDataVec_[iNode];
}